package com.lemobar.pay.service.impl.epay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lemobar.pay.config.EPayConfig;
import com.lemobar.pay.constants.EPayConstants;
import com.lemobar.pay.model.*;
import com.lemobar.pay.model.epay.EPayApi;
import com.lemobar.pay.model.epay.request.EPayQueryRequest;
import com.lemobar.pay.model.epay.request.EPayRefundRequest;
import com.lemobar.pay.model.epay.request.EPayUnifiedCreateRequest;
import com.lemobar.pay.model.epay.response.*;
import com.lemobar.pay.service.impl.LmbPayServiceImpl;
import com.lemobar.pay.utils.*;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import org.apache.commons.codec.digest.DigestUtils;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;

import java.io.IOException;
import java.util.List;
import java.util.Optional;


@Slf4j
public class EPayServiceImpl extends LmbPayServiceImpl {

    protected EPayConfig ePayConfig;

    protected final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(EPayConstants.EPAY_GATEWAY)
            .addConverterFactory(GsonConverterFactory.create())
            .client(new OkHttpClient.Builder()
                    .addInterceptor((new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)))
                    .build()
            ).build();

    protected final Retrofit retrofitQ = new Retrofit.Builder()
            .baseUrl(EPayConstants.EPAY_GATEWAY_Q)
            .addConverterFactory(SimpleXmlConverterFactory.create())
            .client(new OkHttpClient.Builder()
                    .addInterceptor((new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)))
                    .build()
            ).build();

    @Override
    public void setEPayConfig(EPayConfig ePayConfig) {
        this.ePayConfig = ePayConfig;
    }

    @Override
    public PayResponse pay(PayRequest request) {
        EPayUnifiedCreateRequest ePayUnifiedCreateRequest = new EPayUnifiedCreateRequest();
        ePayUnifiedCreateRequest.setMerNo(ePayConfig.getMerNo());
        ePayUnifiedCreateRequest.setIsSubMerPay("0");
        ePayUnifiedCreateRequest.setAppId(ePayConfig.getAppId());
        ePayUnifiedCreateRequest.setAmount(request.getOrderAmount());
        ePayUnifiedCreateRequest.setBillNo(request.getOrderId());
        ePayUnifiedCreateRequest.setPaymentType(request.getPayTypeEnum().getCode());
        ePayUnifiedCreateRequest.setSubject(request.getOrderName());
        ePayUnifiedCreateRequest.setUserId(request.getOpenid());
        ePayUnifiedCreateRequest.setNotifyURL(StringUtil.isEmpty(request.getNotifyUrl()) ? ePayConfig.getNotifyUrl() : request.getNotifyUrl());
        ePayUnifiedCreateRequest.setMD5info(generateMD5info(ePayUnifiedCreateRequest));

        Call<List<EPayUnifiedCreateResponse>> call = retrofit.create(EPayApi.class).create((MapUtil.buildMap(ePayUnifiedCreateRequest)));
        Response<List<EPayUnifiedCreateResponse>> retrofitResponse = null;
        try {
            retrofitResponse = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert retrofitResponse != null;
        if (!retrofitResponse.isSuccessful()) {
            throw new RuntimeException("【双乾支付下单】 网络异常");
        }
        assert retrofitResponse.body() != null;
        System.out.println(retrofitResponse.body());
        EPayUnifiedCreateResponse ePayUnifiedCreateResponse = retrofitResponse.body().get(0);

        String wxjsapiStr = ePayUnifiedCreateResponse.getWxjsapiStr();      // 微信jsapi字符串
        JSONObject wxjsapiJsonObject = (JSONObject)JSON.parse(wxjsapiStr);

        PayResponse payResponse = new PayResponse();
        payResponse.setResultCode(ePayUnifiedCreateResponse.getRespCode());
        payResponse.setErrCode(ePayUnifiedCreateResponse.getRespCode());
        payResponse.setErrCodeDes(ePayUnifiedCreateResponse.getRespMess());

        Optional.ofNullable(wxjsapiJsonObject).ifPresent(o->{   // 微信jsapi字符串 解析
            payResponse.setAppId(o.getString("appId"));
            payResponse.setTimeStamp(o.getString("timeStamp"));
            payResponse.setNonceStr(o.getString("nonceStr"));
            payResponse.setPackAge(o.getString("package"));
            payResponse.setSignType(o.getString("signType"));
            payResponse.setPaySign(o.getString("paySign"));
        });
        payResponse.setOutOrderId(ePayUnifiedCreateResponse.getOrderNo());      // 双乾支付流水
        payResponse.setChannelNo(ePayUnifiedCreateResponse.getChannelNo());     // 支付宝js里tradeNo值
        return payResponse;
    }

    @Override
    public QueryResponse query(QueryRequest queryRequest) {
        EPayQueryRequest request = new EPayQueryRequest();
        request.setMerNo(ePayConfig.getMerNo());
        request.setBillNo(queryRequest.getOrderId());
        request.setMD5Info(generateQueryMD5Info(request));

        Call<EPayQueryResponse> call = retrofitQ.create(EPayApi.class).query((MapUtil.buildMap(request)));
        Response<EPayQueryResponse> retrofitResponse = null;
        try {
            retrofitResponse = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert retrofitResponse != null;
        if (!retrofitResponse.isSuccessful()) {
            throw new RuntimeException("【双乾支付查单】 网络异常");
        }
        assert retrofitResponse.body() != null;
        System.out.println(retrofitResponse.body());
        EPayQueryResponse response = retrofitResponse.body();


        MerInfo merInfo = response.getMerInfo();
        OrderInfo orderInfo = null;
        if(merInfo.getOrderInfoList()!=null){
            orderInfo = merInfo.getOrderInfoList().get(0);
        }
        /*
        订单状态
            0	失败
            1	成功
            2	待处理
            3	取消
            4	结果未返回
         */
        QueryResponse queryResponse = QueryResponse.builder()
                .resultCode(merInfo.getResultCode())
                .errCode("")
                .errCodeDes("")
                .orderId(merInfo.getBillNo())
                .outOrderId(orderInfo == null ? "" : orderInfo.getOrderNo())
                .openid("") // 双乾支付查询 没有
                .orderStatus(orderInfo.getState())
                .orderAmount(orderInfo == null ? null : Double.valueOf(orderInfo.getAmount()))
                .finishTime(orderInfo == null ? null : DateUtil.toDate(orderInfo.getDate()))
                .build();
        return queryResponse;
    }

    @Override
    public RefundResponse refund(RefundRequest request) {
        EPayRefundRequest ePayRefundRequest = new EPayRefundRequest();
        ePayRefundRequest.setMerchantno(ePayConfig.getMerNo());
        ePayRefundRequest.setMerchantOrderNo(request.getOrderId());
        ePayRefundRequest.setOrderNo(request.getOutOrderId());
        ePayRefundRequest.setAmount(String.valueOf(request.getRefundAmount()));
        ePayRefundRequest.setRefundReason(request.getRefundReason());
        ePayRefundRequest.setMd5Info(generateRefundMD5Info(ePayRefundRequest));

        Call<EPayRefundResponse> call = retrofit.create(EPayApi.class).refund((MapUtil.buildMap(ePayRefundRequest)));
        Response<EPayRefundResponse> retrofitResponse = null;
        try {
            retrofitResponse = call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        assert retrofitResponse != null;
        if (!retrofitResponse.isSuccessful()) {
            throw new RuntimeException("【双乾支付退单】 网络异常");
        }
        assert retrofitResponse.body() != null;
        System.out.println(retrofitResponse.body());
        EPayRefundResponse response = retrofitResponse.body();
        return RefundResponse.builder()
                .resultCode(response.getResult())   // 申请结果，如error申请失败 success成功
                .outRefundId(response.getRefundNo()).build();
    }

    /**
     * 生成 退款 MD5Info
     * @param ePayRefundRequest
     * @return MD5Info
     */
    private String generateRefundMD5Info(EPayRefundRequest ePayRefundRequest) {
        //md5Info=MD5("merchantno=168885&merchantOrderNo=123456789&orderNo=123456443333&amount=10.25&"+MD5("12345678").toUpperCase()).toUpperCase();
        String toSign = String.format("merchantno=%s&merchantOrderNo=%s&orderNo=%s&amount=%s&",
                ePayRefundRequest.getMerchantno(),
                ePayRefundRequest.getMerchantOrderNo(),
                ePayRefundRequest.getOrderNo(),
                ePayRefundRequest.getAmount());
        return (DigestUtils.md5Hex(toSign + DigestUtils.md5Hex(ePayConfig.getMd5Key()).toUpperCase())).toUpperCase();
    }

    /**
     * 生成 查单 MD5Info
     * @param ePayQueryRequest
     * @return MD5Info
     */
    private String generateQueryMD5Info(EPayQueryRequest ePayQueryRequest) {
        //MD5Info=MD5("BillNo=1383274623265&MerNo=168885&"+MD5("12345678").toUpperCase()).toUpperCase();
        String toSign = String.format("BillNo=%s&MerNo=%s&",
                ePayQueryRequest.getBillNo(),
                ePayQueryRequest.getMerNo());
        return (DigestUtils.md5Hex(toSign + DigestUtils.md5Hex(ePayConfig.getMd5Key()).toUpperCase())).toUpperCase();
    }

    /**
     * 生成 下单 MD5info
     * @param ePayUnifiedCreateRequest
     * @return MD5info
     */
    private String generateMD5info(EPayUnifiedCreateRequest ePayUnifiedCreateRequest) {
        String toSign = String.format("Amount=%s&BillNo=%s&MerNo=%s&PayType=%s&",
                ePayUnifiedCreateRequest.getAmount(),
                ePayUnifiedCreateRequest.getBillNo(),
                ePayUnifiedCreateRequest.getMerNo(),
                ePayUnifiedCreateRequest.getPayType());
//        MD5info=MD5("Amount=0.01&BillNo=1481093236896&MerNo=168885&PayType=SMZF &"+MD5("12345678").toUpperCase()).toUpperCase();
        return (DigestUtils.md5Hex(toSign + DigestUtils.md5Hex(ePayConfig.getMd5Key()).toUpperCase())).toUpperCase();
//
    }
}
